# 闭包
"""
外函数嵌套子函数，外函数返回的是子函数的地址值
"""
# 写一个每次调用自己增长一的函数
def out():
    num = 0     # 局部变量
    def get():
        nonlocal num            # nonlocal 可以修改局部变量的值
        num+=1
        return num
    return get      # 地址值    ()缺少。没有加括号不能算作调用，返回的就是地址值
"""
num = out()
print(num()) # 1        加上()
print(num()) # 2
print(num()) # 3
"""
def student():
    pass
# print(student)

# 这么调用的话，相当于每次都是首次调用
"""
print(out()())      # 1
print(out()())      # 1
print(out()())      # 1
"""
# 装饰器
"""
在不改变原来的方法调用、内容的前提下，增加一些新的功能
"""
def run():
    print("跑步")
# 我想为run方法加一个健身，不改变原来的代码以及调用方式
"""
def run():
    print("跑步")
    print("健身")
def runs():
    print("跑步")
    print("健身")
"""
# runs()
# 这一次，我想看到跑步和健身
# run()
# 这一次，我只是想看到跑步功能
# run()

# 装饰器怎么实现上面的功能

def paobu(func):
    def luoji():
        func()
        print("健身")
    return luoji
# run()
# 加了装饰器
# print("=============加了装饰器=================")
# a = paobu(run)
# a()
"""
def aaa(func):
    def bbb(num):
        print("装饰之前....")
        num = func(num)        # 拿到原来方法返回值
        num+=100            # +100再返回
        print("装饰之后....")
        return num      # 返回num
    return bbb
@aaa            # 简化引用装饰器
def add(num):
    print(f"我是{num}")
    return num
print(add(50))
"""
"""
装饰之前....
我是num
print("装饰之后....")
150
"""


# 异常捕捉
"""
try:
    list1 = [10,20,30,40]
    print(list1[9])
except Exception as _:      # Exception万能捕捉，任何异常都会捕捉并使用
    print(f"报错了：{_}")
except IndexError as e:
    print(f"报错了：{e}")
else:
    print("代码无异常")
finally:
    print("代码运行结束")
"""
"""
try：
    尝试执行的代码
except：
    如果报错，执行这里
else：
    如果没报错，执行这里
finally：
    不管执行成功与否他都会执行
"""

# 迭代器
"""
i = 0
while True:
    print(i)
    # 单纯的如此循环，不是迭代
"""
# 这个是迭代
"""
list1 = [10,20,30,40]
i = 0
while i<len(list1):
    print(list1[i])
    i+=1
"""
# 迭代器生成
list1 = [10,20,30,40]
# list1.__iter__()        # 说明列表可以创建成迭代器
tuple1 = (10,20,30)
# tuple1.__iter__()       # 元组可以生成迭代器
set1 = {10,20,30}
# set1.__iter__()     # 集合可以生成迭代器
str1 = "102930123"
# str1.__iter__()     # 字符串可以生成迭代器
dict1 = {"s":"a"}
# dict1.__iter__()        # 字典可以生成迭代器
int1 = 101111
# int1.__iter__()     # 整数类型不可以生成迭代器
float1 = 1.1
# float1.__iter__()       # 浮点型不可以生成迭代器

# 用迭代器访问下一次元素内容
list2 = [1,2,3,4,5]
"""
list_iter = list2.__iter__()        # 创建一个列表迭代器
print(list_iter.__next__()) # 访问下一次的内容：1
print(list_iter.__next__()) # 访问下一次的内容：2
print(list_iter.__next__()) # 访问下一次的内容：3
print(list_iter.__next__()) # 访问下一次的内容：4
print(list_iter.__next__()) # 访问下一次的内容：5
"""
# print(list_iter.__next__()) # 访问下一次的内容：StopIteration

#有个误区，这样每次都是取第一个了
"""
print(list2.__iter__().__next__())
print(list2.__iter__().__next__())
print(list2.__iter__().__next__())
print(list2.__iter__().__next__())
print(list2.__iter__().__next__())
print(list2.__iter__().__next__())
print(list2.__iter__().__next__())
print(list2.__iter__().__next__())
print(list2.__iter__().__next__())
"""

# for循环，实际上就是遍历+兜底不会报错
# for i in list2:
#     print(i)
"""
把要遍历的对象变成迭代器
然后去每次访问下一个
直到访问最后一个的时候，停止，不会报错
"""
"""
iter = list2.__iter__()
while True:
    try:
        print(next(iter))
    except StopIteration:
        break
"""

#生成器 yield
def g():
    a = 1
    while True:     # 死循环，可以调用多次
        yield a     # yield ，生成器。生成器也是属于迭代器的一种，但是只能迭代一次
        # 你可以把yield当成return，下次再调用这个函数的时候，会从下向上执行
        a += 1

# a = g()
# print(next(a))      # 1
# print(next(a))      # 2








